'''
Created on 2010-4-26
this file contains the WSGI middleware for session.
@author: watson
''' 
import uuid
import json
from time import time
from google.appengine.api import memcache
from google.appengine.ext import db
import logging
import threading

class SessionEntity(db.Expando):
  sid = db.StringProperty()

class SessionIdNotExist(Exception):
  pass

class SessionNotExist(Exception):
  pass

class SessionRepo(object):
  @staticmethod
  def load_session(sid):
    """ return a seesion object by sid
    """
    session = dict()
    
    #get the session data diction from memcache
    data = memcache.Client().get(sid)
    if data is not None:
      session = json.loads(data)
    else:
      #load session in datastore
      sessionEntity = SessionEntity.gql("WHERE sid = :1", sid).get()
      if sessionEntity is not None:
        for pname in sessionEntity.dynamic_properties():
          session[pname] = sessionEntity.__getattribute__(pname); 
      else:
        raise SessionNotExist()
    
    return session
  
  @staticmethod
  def create_session():
    session = dict()
    sid = uuid.uuid4()
    #create a data entry in memcache for the session
    if not memcache.Client.add(sid, json.dumps(session), 300): #expired in 300 seconds.
      logging.warning('add session into memcache fail!');
    
    #create data entry in datastore also
    sessionEntity = SessionEntity()
    sessionEntity.sid = sid
    sessionEntity.put()  #what if put() raise exception?
    
    return (sid, session)  
  
  @staticmethod
  def flush_session(sid, session):
    """ flush the session to persist storage
    """
    #update a data entry in memcache for the session
    if not memcache.Client.set(sid, json.dumps(session), 300): #expired in 300 seconds.
      logging.warning('flush session into memcache fail!');
    
    #update data entry in datastore also
    sessionEntity = SessionEntity.gql("WHERE sid = :1", sid).get()
    if sessionEntity is not None:
      for pname in session.keys():
        sessionEntity.__setattr__[pname] = session[pname] 
    else:
      #no sessionEntity found?! something happend.
      raise SessionNotExist()
    sessionEntity.put()  #what if put() raise exception?

class SessionHandler(object):
  """
  private class, a session handler in wsgi middleware format.
  """ 
  def __init__(self, application):
    self.__application = application

  def __call__(self, env, start_response):
    logging.debug(env)
    if env.has_key('WATSON_SID'):
      session = SessionRepo.load_session(env['WATSON_SID'])
    else:
      (sid,session) = SessionRepo.create_session()
       
    self.__application(env, self.start_response)
    if not env.has_key('WATSON_SID'):
        self.__response_headers.append(tuple('WATSON', sid))
    write = start_response(self.__status, self.__response_headers)
    write(self.__body)
    SessionRepo.flush_session()
  
  def start_response(self, status, response_headers, exc_info=None):
    self.__status = status
    self.__response_headers = response_headers
    self.__exc_info = exc_info
    return self.write
  
  def write(self, body):
    self.__body = body
    
  
  